//
//  TiaoyinViewController.swift
//  Duyiguqin
//
//  Created by 张昭 on 2024/8/4.
//

import UIKit
import AVFoundation
import Accelerate

class TiaoyinViewController: BaseViewController {
    
    deinit {
        // Remove observer
        NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardWillShowNotification, object: nil)
        NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardWillHideNotification, object: nil)
        audioEngine.stop()
        debugPrint("TiaoyinViewController init")
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        initializeSubviews()
        loadScripts()
        setDefaultConfig()
        setupAudioEngine()
        setupFFT()
        updateStandardHZ()
    }

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        headerView.update(HZ: -90)
    }
    
    override func viewDidDisappear(_ animated: Bool) {
        super.viewDidDisappear(animated)
        audioEngine.stop()
    }
    
    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
        scrollView.contentSize = CGSize(width: UIScreen.main.bounds.size.width, height: 740)
    }
    
    override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
        guard let touchPoint = touches.first?.location(in: view) else { return }
        guard !textFieldBgView.frame.contains(touchPoint) else { return }
        view.endEditing(true)
    }
    
    private let headerView = TiaoyinHeaderView()
    
    private lazy var footerView: UIView = {
        let v = UIView()
        v.backgroundColor = .white
        v.layer.shadowColor = UIColor.black.cgColor
        v.layer.shadowOpacity = 0.05
        v.layer.shadowOffset = CGSize(width: 0, height: 5)
        v.layer.shadowRadius = 15
        v.layer.cornerRadius = 10
        v.clipsToBounds = false
        return v
    }()
    
    private lazy var hzButton: UIButton = {
        let v = UIButton(type: .custom)
        v.layer.cornerRadius = 5
        v.layer.masksToBounds = true
        v.layer.borderWidth = 1.0
        v.layer.borderColor = UIColor(0xF2F2F2).cgColor
        v.setTitle("440HZ", for: .normal)
        v.setTitleColor(UIColor.black, for: .normal)
        v.titleLabel?.font = UIFont.systemFont(ofSize: 15, weight: .bold)
        v.contentEdgeInsets = UIEdgeInsets(top: 0, left: 8, bottom: 0, right: 8)
        v.addTarget(self, action: #selector(onClickHZButton(_:)), for: .touchUpInside)
        v.setContentCompressionResistancePriority(.required, for: .horizontal)
        return v
    }()
    
    private lazy var toneButton: UIButton = {
        let v = UIButton(type: .custom)
        v.backgroundColor = UIColor(0xF2F2F2)
        v.layer.cornerRadius = 12
        v.layer.masksToBounds = true
        v.setTitleColor(UIColor.black, for: .normal)
        v.titleLabel?.font = UIFont.systemFont(ofSize: 15, weight: .bold)
        v.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
        v.addTarget(self, action: #selector(onClickToneButton(_:)), for: .touchUpInside)
        v.contentEdgeInsets = UIEdgeInsets(top: 0, left: 8, bottom: 0, right: 8)
        return v
    }()
    
    private lazy var qinBgView: UIView = {
        let v = UIView()
        v.backgroundColor = UIColor(0xB2B2B2)
        v.layer.cornerRadius = 6
        v.layer.masksToBounds = true
        return v
    }()
    
    private lazy var qinImageView: UIImageView = {
        let v = UIImageView()
        v.image = UIImage(resource: .iconQin)
        v.contentMode = .scaleAspectFit
        return v
    }()
    
    private lazy var switchButton: UISwitch = {
        let v = UISwitch()
        v.onTintColor = UIColor(0xD3C390)
        v.isOn = true
        v.addTarget(self, action: #selector(onSwitchButtonTapped(_:)), for: .valueChanged)
        v.setContentCompressionResistancePriority(.required, for: .horizontal)
        return v
    }()
    
    private lazy var switchLabel: UILabel = {
        let v = UILabel()
        v.text = "自动"
        v.font = UIFont.systemFont(ofSize: 13, weight: .regular)
        v.textColor = .black
        v.setContentCompressionResistancePriority(.required, for: .horizontal)
        return v
    }()

    private lazy var bottomView: UIView = {
        let v = UIView()
        v.backgroundColor = .white
        v.layer.cornerRadius = 12.5
        v.layer.masksToBounds = true
        return v
    }()
    
    private lazy var iconImageView: UIImageView = {
        let v = UIImageView()
        v.image = UIImage(resource: .iconAlert)
        return v
    }()
    
    private lazy var descLabel: UILabel = {
        let v = UILabel()
        v.text = "请在尽可能安静的环境下完成调音"
        v.font = UIFont.systemFont(ofSize: 11, weight: .medium)
        v.textColor = UIColor(0x808080)
        return v
    }()
    
    private lazy var scrollView: UIScrollView = {
        let v = UIScrollView()
        v.backgroundColor = .clear
        return v
    }()
    
    private lazy var textFieldBgView: UIView = {
        let v = UIView()
        v.backgroundColor = .white
        v.layer.shadowColor = UIColor.black.cgColor
        v.layer.shadowOpacity = 0.05
        v.layer.shadowOffset = CGSize(width: 0, height: 5)
        v.layer.shadowRadius = 15
        v.layer.cornerRadius = 10
        return v
    }()
    
    private lazy var textField: UITextField = {
        let v = UITextField()
        v.keyboardType = .numberPad
        v.delegate = self
        v.text = "440"
        return v
    }()
    
    private lazy var textFieldConfirmButton: UIButton = {
        let v = UIButton(type: .custom)
        v.setTitle("确定", for: .normal)
        v.setTitleColor(UIColor(0xD3C390), for: .normal)
        v.setTitleColor(UIColor(0xD3C390).withAlphaComponent(0.6), for: .highlighted)
        v.titleLabel?.font = UIFont.systemFont(ofSize: 15, weight: .bold)
        v.addTarget(self, action: #selector(onClickTextFieldConfirmButton(_:)), for: .touchUpInside)
        return v
    }()
    
    private var audioEngine: AVAudioEngine!
    private var inputNode: AVAudioInputNode!
    private var bufferSize: AVAudioFrameCount = 1024
    private var fftSetup: FFTSetup!
    private var itemsView: [UIButton] = []
    
    private var selectedTone: Tone = .F {
        didSet {
            let items = selectedTone.pitchs
            for i in 0..<items.count {
                let title = items[i].0
                if i < itemsView.count {
                    let v = itemsView[i]
                    v.setTitle(title, for: .normal)
                }
            }
        }
    }
    private var selectedPitchIndex: Int = 0 {
        didSet {
            let hz = Int(textField.text ?? "0") ?? 0
            guard selectedPitchIndex < selectedTone.pitchs.count else {
                return
            }
            let value = self.selectedTone.pitchs[selectedPitchIndex].1 * Double(hz)
            self.headerView.update(SHZ: value)
            if selectedPitchIndex < itemsView.count {
                itemsView[selectedPitchIndex].isSelected = true
            }
            self.headerView.update(Xian: selectedPitchIndex + 1)
        }
    }
}

extension TiaoyinViewController {
    
    private func initializeSubviews() {
        
        titleLabel.text = "古琴调音"
        view.addSubview(scrollView)
        scrollView.snp.makeConstraints { make in
            make.left.right.equalTo(0)
            make.top.equalTo(naviHeaderView.snp.bottom)
            make.bottom.equalTo(0)
        }
        
        scrollView.addSubview(headerView)
        headerView.snp.makeConstraints { make in
            make.top.equalTo(20)
            make.left.equalTo(15)
            make.right.equalTo(-15)
            make.width.equalTo(UIScreen.main.bounds.size.width - 30)
        }
        
        scrollView.addSubview(footerView)
        footerView.snp.makeConstraints { make in
            make.top.equalTo(headerView.snp.bottom).offset(20)
            make.left.right.equalTo(headerView)
        }
        
        footerView.addSubview(hzButton)
        hzButton.snp.makeConstraints { make in
            make.height.equalTo(30)
            make.top.equalTo(15)
            make.left.equalTo(10)
        }
        
        footerView.addSubview(toneButton)
        toneButton.snp.makeConstraints { make in
            make.height.equalTo(30)
            make.top.equalTo(hzButton)
            make.left.equalTo(hzButton.snp.right).offset(10)
        }
        
        footerView.addSubview(switchButton)
        switchButton.snp.makeConstraints { make in
            make.right.equalTo(-10)
            make.centerY.equalTo(hzButton)
        }
        
        footerView.addSubview(switchLabel)
        switchLabel.snp.makeConstraints { make in
            make.right.equalTo(switchButton.snp.left).offset(-5)
            make.centerY.equalTo(switchButton)
        }
        
        footerView.addSubview(qinBgView)
        qinBgView.snp.makeConstraints { make in
            make.left.equalTo(10)
            make.top.equalTo(toneButton.snp.bottom).offset(15)
            make.right.equalTo(-50)
            make.bottom.equalTo(-11)
        }
        
        qinBgView.addSubview(qinImageView)
        qinImageView.snp.makeConstraints { make in
            make.top.equalTo(14)
            make.bottom.equalTo(-14)
            make.height.equalTo(176)
            make.right.lessThanOrEqualToSuperview()
            make.left.equalTo(0)
        }
        
        var lastView: UIView?
        for i in 0..<7 {
            let btn = UIButton(type: .custom)
            btn.setTitleColor(UIColor.black, for: .normal)
            btn.setTitleColor(UIColor.white, for: .selected)
            btn.titleLabel?.font = UIFont.systemFont(ofSize: 15, weight: .bold)
            btn.setBackgroundImage(UIImage.color(UIColor(0xF2F2F2)), for: .normal)
            btn.setBackgroundImage(UIImage.color(UIColor(0xD3C390)), for: .selected)
            btn.layer.cornerRadius = 12.5
            btn.layer.masksToBounds = true
            btn.addTarget(self, action: #selector(onClickItemButton(_:)), for: .touchUpInside)
            footerView.addSubview(btn)
            btn.tag = i + 1
            btn.snp.makeConstraints { make in
                make.size.equalTo(25)
                if let v = lastView {
                    make.top.equalTo(v.snp.bottom).offset(5)
                } else {
                    make.top.equalTo(qinBgView)
                }
                make.left.equalTo(qinBgView.snp.right).offset(15)
            }
            itemsView.append(btn)
            lastView = btn
        }
        
        scrollView.addSubview(bottomView)
        bottomView.snp.makeConstraints { make in
            make.top.equalTo(footerView.snp.bottom).offset(15)
            make.centerX.equalTo(headerView)
            make.height.equalTo(25)
        }
        
        bottomView.addSubview(iconImageView)
        iconImageView.snp.makeConstraints { make in
            make.left.equalTo(12.5)
            make.size.equalTo(12)
            make.centerY.equalToSuperview()
        }
        
        bottomView.addSubview(descLabel)
        descLabel.snp.makeConstraints { make in
            make.centerY.equalToSuperview()
            make.left.equalTo(iconImageView.snp.right).offset(9)
            make.right.equalTo(-13)
        }
        
        view.addSubview(textFieldBgView)
        textFieldBgView.snp.makeConstraints { make in
            make.bottom.equalTo(40)
            make.height.equalTo(40)
            make.left.equalTo(20)
            make.right.equalTo(-20)
        }
        
        textFieldBgView.addSubview(textFieldConfirmButton)
        textFieldConfirmButton.snp.makeConstraints { make in
            make.right.equalTo(0)
            make.top.bottom.equalTo(0)
            make.width.equalTo(60)
        }
        
        textFieldBgView.addSubview(textField)
        textField.snp.makeConstraints { make in
            make.left.equalTo(20)
            make.centerY.equalToSuperview()
            make.right.equalTo(textFieldConfirmButton.snp.left).offset(-10)
        }
        
        textFieldConfirmButton.setContentCompressionResistancePriority(.required, for: .horizontal)
    }
    
    private func loadScripts() {
        NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow(_:)), name: UIResponder.keyboardWillShowNotification, object: nil)
        NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide(_:)), name: UIResponder.keyboardWillHideNotification, object: nil)
    }
    
    private func setDefaultConfig() {
        self.toneButton.setTitle(Tone.F.shortTitle, for: .normal)
        self.selectedTone = Tone.F
        self.switchButton.isOn = true
        self.hzButton.setTitle("440HZ", for: .normal)
        self.textField.text = "440"
        self.selectedPitchIndex = 0
    }
    
    private func updateStandardHZ() {
        
        
    }
    
    @objc private func onClickTextFieldConfirmButton(_ sender: UISwitch) {
        textField.resignFirstResponder()
        guard let hz = Int(textField.text ?? "0") else { return }
        hzButton.setTitle("\(hz)HZ", for: .normal)
        let idx = selectedPitchIndex
        selectedPitchIndex = idx
    }
    
    @objc private func onSwitchButtonTapped(_ sender: UISwitch) {
        textField.resignFirstResponder()
    }
    
    @objc private func onClickHZButton(_ sender: UISwitch) {
        textField.becomeFirstResponder()
    }
    
    @objc private func onClickToneButton(_ sender: UIButton) {
        let vc = ToneSelectViewController(tone: selectedTone)
        vc.onSubmit = { [weak self] tone in
            self?.toneButton.setTitle(tone.shortTitle, for: .normal)
            self?.selectedTone = tone
            let idx = self?.selectedPitchIndex ?? 0
            self?.selectedPitchIndex = idx
        }
        navigationController?.present(vc, animated: true)
    }
    
    @objc private func onClickItemButton(_ sender: UIButton) {
        textField.resignFirstResponder()
        for btn in itemsView {
            if btn == sender {
                btn.isSelected = true
            } else {
                btn.isSelected = false
            }
        }
        headerView.update(Xian: sender.tag)
        let idx = sender.tag - 1
        guard idx < selectedTone.pitchs.count else { return }
        selectedPitchIndex = idx
    }
    
    func setupAudioEngine() {
        audioEngine = AVAudioEngine()
        inputNode = audioEngine.inputNode

        // 获取音频格式
        let format = inputNode.inputFormat(forBus: 0)

        // 检查采样率和通道数
        guard format.sampleRate > 0, format.channelCount > 0 else {
            print("Invalid audio format")
            return
        }

        let bus = 0

        inputNode.installTap(onBus: bus, bufferSize: bufferSize, format: format) { [weak self] (buffer, time) in
            guard let channelData = buffer.floatChannelData?[0] else {
                print("Failed to get channel data")
                return
            }

            let channelDataArray = Array(UnsafeBufferPointer(start: channelData, count: Int(buffer.frameLength)))
            let frequency = self?.calculateFrequency(from: channelDataArray) ?? 0
            print("Frequency: \(frequency) Hz")
            DispatchQueue.main.async {
                let fre = Double(frequency)
                self?.headerView.update(HZ: fre)
            }
        }

        do {
            try audioEngine.start()
        } catch {
            print("Failed to start audio engine:", error)
        }
    }

    func setupFFT() {
        let log2n = UInt(log2(Double(bufferSize)))
        fftSetup = vDSP_create_fftsetup(log2n, Int32(kFFTRadix2))
    }

    func calculateFrequency(from audioData: [Float]) -> Float {
        let halfSize = audioData.count / 2
        var realp = [Float](repeating: 0.0, count: halfSize)
        var imagp = [Float](repeating: 0.0, count: halfSize)
        
        
        var complexBuffer = DSPSplitComplex(realp: &realp, imagp: &imagp)
        audioData.withUnsafeBufferPointer { bufferPointer in
            vDSP_ctoz(UnsafePointer<DSPComplex>(OpaquePointer(bufferPointer.baseAddress!)), 2, &complexBuffer, 1, vDSP_Length(halfSize))
        }
        
        vDSP_fft_zrip(fftSetup, &complexBuffer, 1, vDSP_Length(log2(Double(bufferSize))), Int32(kFFTDirection_Forward))
        
        var magnitudes = [Float](repeating: 0.0, count: halfSize)
        vDSP_zvmags(&complexBuffer, 1, &magnitudes, 1, vDSP_Length(halfSize))
        
        let maxMagnitudeIndex = magnitudes.firstIndex(of: magnitudes.max() ?? 0) ?? 0
        let frequency = Float(maxMagnitudeIndex) * Float(audioEngine.inputNode.outputFormat(forBus: 0).sampleRate) / Float(bufferSize)
        
        return frequency
    }
    
    @objc func keyboardWillShow(_ notification: Notification) {
        scrollView.isUserInteractionEnabled = false
        if let userInfo = notification.userInfo,
           let keyboardFrame = userInfo[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect {
            // Adjust bottom constraint based on keyboard height
            let keyboardHeight = keyboardFrame.height
            textFieldBgView.transform = CGAffineTransform(translationX: 0, y: -keyboardHeight - 40)
        }
    }

    @objc func keyboardWillHide(_ notification: Notification) {
        scrollView.isUserInteractionEnabled = true
        textFieldBgView.transform = CGAffineTransform.identity
    }
}

extension TiaoyinViewController: UITextFieldDelegate {
    
    func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
        if !string.isEmpty {
            let str = NSString(string: "0123456789")
            if str.range(of: string).length == 0 {
                return false
            }
            let old = textField.text ?? ""
            if old == "0" && !string.isEqual("0") {
                textField.text = string
                return false
            }
        }
        let currentText = (textField.text as NSString?)?.replacingCharacters(in: range, with: string) ?? string
        if currentText.count > 10 {
            return false
        }
        return true
    }
}
